/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package TimeRecording.TimeClockServer;

import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @author david
 */
public abstract class MessageFormatter {

    public final static String EOT_TOKEN = "[EOT]";
    public final static String EOT_REPLACEMENT = "\004";

    public final static String TAB_TOKEN = "[TAB]";
    public final static String TAB_REPLACEMENT = "\011";

    public final static String FS_TOKEN = "[FS]";
    public final static String FS_REPLACEMENT = "\034";

    public final static String GS_TOKEN = "[GS]";
    public final static String GS_REPLACEMENT = "\035";

    public final static String RS_TOKEN = "[RS]";
    public final static String RS_REPLACEMENT = "\036";

    public final static String US_TOKEN = "[US]";
    public final static String US_REPLACEMENT = "\037";

    public final static String HDR_TOKEN = "[HDR]";
    public final static String HDR_REPLACEMENT = "\\A!\035";

    public static byte[] textToBytes(String text) {

        StringBuffer msg = new StringBuffer(text);
        replaceToken(msg, EOT_TOKEN, EOT_REPLACEMENT);
        replaceToken(msg, HDR_TOKEN, HDR_REPLACEMENT);
        replaceToken(msg, TAB_TOKEN, TAB_REPLACEMENT);
        replaceToken(msg, FS_TOKEN, FS_REPLACEMENT);
        replaceToken(msg, GS_TOKEN, GS_REPLACEMENT);
        replaceToken(msg, RS_TOKEN, RS_REPLACEMENT);
        replaceToken(msg, US_TOKEN, US_REPLACEMENT);
        text = msg.toString();
        
        // Convert the string into a byte array

        byte[] bytes = new byte[text.length()];
        for (int index = 0; index < text.length(); index++) {
            int character = text.charAt(index);
            bytes[index] = (byte)character;
        }

        return bytes;
    }

    public static String bytesToText(byte[] bytes) {

        StringBuffer text = new StringBuffer(new String(bytes));
        replaceToken(text, EOT_REPLACEMENT, EOT_TOKEN);
        replaceToken(text, HDR_REPLACEMENT, HDR_TOKEN);
        replaceToken(text, TAB_REPLACEMENT, TAB_TOKEN);
        replaceToken(text, FS_REPLACEMENT, FS_TOKEN);
        replaceToken(text, GS_REPLACEMENT, GS_TOKEN);
        replaceToken(text, RS_REPLACEMENT, RS_TOKEN);
        replaceToken(text, US_REPLACEMENT, US_TOKEN);
        return text.toString();
    }

    public static void replaceToken(
            StringBuffer buffer, String search, String replace) {

        int offset = buffer.indexOf(search);
        while (offset != -1) {
            buffer.replace(offset, offset + search.length(), replace);
            offset = buffer.indexOf(search);
        }
    }

    /**
     * Splits the supplied message into it's component parts.  The basis for
     * splitting is the presence of separators (any non-printing characters).
     * Note the following:
     *
     *  - The separators are included as separate entries in the array.
     *  - The passed message must be in binary form; mnemonic will not be
     *    recognised.
     *
     * @param bytes the message to spilt (in binary form)
     * @return a de-constructed message in the form of an array of parts
     */
    public static String[] splitMessage(byte[] bytes) {

        ArrayList<String> tokens = new ArrayList<String>();
        StringBuilder token = new StringBuilder();

        // Skip the header (we can safely assume there is one)
        int offset = MessageFormatter.HDR_REPLACEMENT.length();
        tokens.add(MessageFormatter.HDR_REPLACEMENT);

        while (offset < bytes.length) {

            byte nextByte = bytes[offset];

            // Is this a control code?
            if (nextByte < 32) {

                // Did we have a previous in-progress token?
                if (token.length() > 0) {

                    // Flush our in-progress token
                    tokens.add(token.toString());
                    token.setLength(0);
                }

                // Add our new control code as a separate token
                // (separators are always a single character)
                tokens.add(new String(new byte[] { nextByte }));

            } else {

                // It was an alpha-numeric... just tag it onto the current token
                token.append((char)nextByte);
            }

            offset++;
        }

        // Did we have an in-progress token that we can flush?
        if (token.length() > 0) {
            tokens.add(token.toString());
        }
        
        return tokens.toArray(new String[0]);
    }
}